/*
 * Sensor.cpp
 *
 *  Created on: Mar 2, 2012
 *      Author: Hieutran
 */
#include "Sensor.h"

Define_Module(Sensor);

void Sensor::initialize() {
    //
    this->id = getId();

    this->xpos = par("xpos");
    this->ypos = par("ypos");
    this->status = STT_IS_NORMAL;
    this->energy = getParentModule()->par("energy");
    this->energyMax = energy;
    this->p = getParentModule()->par("p");

    this->protocol = getParentModule()->par("protocol");
    this->k1 = getParentModule()->par("K1");
    this->k2 = getParentModule()->par("K2");
    this->k3 = getParentModule()->par("K3");
    this->k4 = getParentModule()->par("K4");

    WATCH(energy);
    WATCH(distance2BS);
    WATCH(status);
    WATCH(currRound);
    WATCH(k1);
    WATCH(k2);
    WATCH(k3);
    WATCH(k4);
    WATCH(relayNodeGate);

    WATCH(isInEvent);
    this->numberFrame = getParentModule()->par("dataPacketPerRound");
    this->pixel2meterRatio = par("pixel2meterRatio");

    this->transmitRange = par("transmitRange");
    this->sensorRange = getParentModule()->par("sensorRangeWSN");
    clusterMember = new cArray();

    this->currRound = -1;
    resetRound();

    cMessage *cmsg = new cMessage();
    cmsg->setKind(MSG_INIT);
    scheduleAt(simTime() + 1, cmsg);

}

void Sensor::handleMessage(cMessage *msg) {
    int messageKind = msg->getKind();
    if (msg->isSelfMessage()) {
        ev << "Sensor node " << this->getId() << " got self message type: "
                << msg->getKind() << "\n";
        switch (messageKind) {
        case MSG_MY_GEN_EVENT:
            hanndleMyGenEvent(msg);
            break;
        case MSG_TDMA: {
            TDMAMessage *mess = new TDMAMessage();
            mess->setKind(MSG_TDMA);
            broadCastMess(mess, 1); //to clustermember
            //cap nhat dataMax tren BS
            BaseStation *bs = (BaseStation*) simulation.getModule(simulation.getLastModuleId());
            if (clusterMember->size() != 0) {
                bs->numberDataMax += numberFrame;
            }

            ev << "Cap nhat numberDataMax tren BS " << bs->numberDataMax
                    << " voi member=" << clusterMember->size() << "\n";
            break;
        }
        case MSG_ENDROUND: {
            ev << "GOi endROund tu BS \n";
            BaseStation *bs = check_and_cast<BaseStation*>(
                    simulation.getModule(simulation.getLastModuleId()));
            bs->endRound();
        }
            break;
        case MSG_DATA2CH:
            handleData2CH_self(msg);
            break;
        case MSG_STATUSINFO: {
            StatusInfo *mess = check_and_cast<StatusInfo*>(msg);
            for (cModule::GateIterator i(this); !i.end(); i++) {
                cGate *gate = i();
                if (gate->getType() == cGate::OUTPUT) {
                    cModule *mod = gate->getPathEndGate()->getOwnerModule();
                    if (strcmp(mod->getClassName(), "BaseStation") == 1) { //Sensor
                        Sensor *sensor = check_and_cast<Sensor *>(
                                gate->getPathEndGate()->getOwnerModule());

                        if (sensor->isInEvent == this->isInEvent) {
                            mySend(mess->dup(), gate, false);
                        }

                    }

                }
            }
            //delete (mess);
            break;
        }

        case MSG_INIT:

            initNodes();
            break;
        case MSG_DATA2RN:

            handleData2RN(msg);
            break;
        }
    } else { //not self message
        if (status != STT_IS_DEATH) {
            Sensor *sensor = (Sensor*) msg->getSenderGate()->getOwnerModule();
            double xlength = this->xpos - sensor->xpos;
            double ylength = this->ypos - sensor->ypos;
            double distance = sqrt(xlength * xlength + ylength * ylength);
            if (messageKind == MSG_DATA2CH || messageKind == MSG_DATA2RN) {
                energyCalculate(messageKind, RECEIVE, distance);
            }
            switch (messageKind) {
            case MSG_DATA2CH:
                handleData2CH_notself(msg);
                break;
            case MSG_CLUSTERJOIN:
                handleClusterHeadJoin(msg);
                break;
            case MSG_TDMA:
                handleTDMA(msg);
                break;
            case MSG_CHADV:
                handleClusterHeadAdv(msg);
                break;
            case MSG_DATA2RN:
                handleData2RN(msg);
                break;
            case MSG_RESET_AND_GEN:
                ev << "Nhay vao reset and gen \n";
                resetRound();
                generateEvent();
                break;
            case MSG_REQRN:



                sendAckRNMess(getOutGate(msg->getArrivalGate()),msg);

                break;
            case MSG_ACKRN:
                numberAck++;
                ev << "Done!" << numberAck << "/" << numberAckMax << "\n";
                if (minAckGate == NULL) {

                    minAckGate = msg->getArrivalGate();
                    minAckValue = check_and_cast<AckRN*>(msg)->getValue();

                    if (protocol == MYPROTOCOL) {
                        minAckCmpValue =
                                check_and_cast<AckRN*>(msg)->getValueCmp();
                    }
                    ev << "set min dau tien \n";

                } else {
                    AckRN *currMess = check_and_cast<AckRN*>(msg);
                    if (currMess->getValue() < minAckValue) {
                        minAckGate = currMess->getArrivalGate();
                        minAckValue = currMess->getValue();
                    }
                    if (protocol == MYPROTOCOL) {
                        if (currMess->getValueCmp() < minAckCmpValue) {
                            minAckCmpGate = currMess->getArrivalGate();
                            minAckCmpValue = currMess->getValueCmp();
                        }
                    }
                }

                if (numberAck == numberAckMax) {
                    relayNodeGate = getOutGate(minAckGate);

                    isFindRN = false;
                    ev << "send data\n";
                    numberAck = 0;
                    //reset some thing
                    minAckCmpGate = NULL;
                    minAckCmpGate = NULL;
                    minAckValue = FMAX;
                    minAckCmpValue = FMAX;

                    if (minAckGate == data2RNMessage->getArrivalGate()) {
                        ev << "Loop detected \n";
                        delete (data2RNMessage);
                        base->numberErrorMessage++;
                        return;
                    }
                    if (protocol == MLEACH) {
                        ev << "Lua chon RelayNode theo MLeach \n";
                        ev.printf("Choose RelayNode fMin=%8.2f \n",
                                minAckValue);
                    } else if (protocol == ARPEES) {
                        ev << "Lua chon RelayNode theo Arpees \n";
                        ev.printf("Choose RelayNode fMin=%8.2f \n",
                                minAckValue);
                    } else if (protocol == MYPROTOCOL) {
                        ev << "Lua chon RelayNode theo MyProtocol \n";
                        ev.printf("Choose RelayNode fMin=%8.2f \n",
                                minAckValue);
                        int myProtocolRelayId =
                                minAckGate->getPathStartGate()->getOwnerModule()->getId();
                        int arpeesRelayId =
                                minAckGate->getPathStartGate()->getOwnerModule()->getId();
                        ev << "Compare MyProtocol relay =" << myProtocolRelayId
                                << ", arpees relay =" << arpeesRelayId << "\n";
                    }

                    //color relay Node
                    if (status != STT_IS_CH) {
                        cDisplayString& connDispStra = getDisplayString();
                        connDispStra.parse(
                                "p=$xpos,$ypos;i=misc/node,red;is=vs");
                    }

                    //color Link
                    cDisplayString& connDispStr =
                            relayNodeGate->getDisplayString();
                    connDispStr.parse("ls=#0080C0,2");
                    mySend(data2RNMessage, relayNodeGate);
                    currNumberData2CH++;
                    //

                }
                break;
            case MSG_STATUSINFO:
                handleStatusInfo(msg);

                break;
            }
        } else {
            if (msg->getKind() == MSG_DATA2RN) {
                base->numberErrorMessage++;
            }
        }
    }
    if (msg != NULL) {
        delete (msg);
    } else {
        ev << "Xay ra NULL POINTER tai delete msg \n";
    }

}
void Sensor::sendAckRNMess(cGate *gate,cMessage* mess) {
    AckRN *ackMess = new AckRN();

    ackMess->setKind(MSG_ACKRN);
    double fn;
    if (protocol == MYPROTOCOL) {
        Sensor *sensor = check_and_cast<Sensor*>(
                gate->getPathEndGate()->getOwnerModule());

        double xlength = this->xpos - sensor->xpos;
        double ylength = this->ypos - sensor->ypos;
        double distance = sqrt(xlength * xlength + ylength * ylength);
        double a, b, c;
        a = distance2BS;
        b = distance;
        c = sensor->distance2BS;
        //Tinh cos
        double cos_temp = (b * b + c * c - a * a) / (2 * b * c);
        //Tinh Ereq
        double e_req = 0;
        e_req = numberFrame * energyTool(MSG_DATA2RN, TRANSMIT, transmitRange)
                + numberNeighbor
                        * energyTool(MSG_REQRN, TRANSMIT, transmitRange)
                + numberNeighbor * energyTool(MSG_ACKRN, RECEIVE, transmitRange)
                + energyMax / 10;
        //Tinh fn theo MyProtocol
        double sin_temp = sqrt(1 - cos_temp * cos_temp);
        //fn = k1 * sin_temp + k2 * a / c + k3 * 1000000 / energy;
        //fn = k1 * sin_temp + k2 * a / c + 1/pow(energy/1000000,k3);
        fn =  sin_temp +  a / c + energyMax/(k3*energy);
        //fn = -energy * (b * b + c * c - a * a) / (2 * c * a);
        //fn=-pow(cos_temp,k1)*pow(b/a,k2)*pow(energy,k3);
        //tinh fn theo arpees
        double fnCmp = -energy * (b * b + c * c - a * a) / (2 * c * a);
        /*
         *
         */ev.printf("Cos = %7.1f \n", cos_temp);
        ev.printf("a = %7.1f b=%7.1f c=%7.1f \n", sin_temp, a / c,
                1 * 1000000 / energy);
        int flag=check_and_cast<RequestRN*>(mess)->getFlag();
        if ((cos_temp > 0 && energy > e_req)) {
            sensor->numberAckMax++;
            ackMess->setValue(fn);
            ackMess->setValueCmp(fnCmp);
            mySend(ackMess, gate, false);
            ev.printf("Compute Ereq=%7.0f < Eres= %7.1f \n", e_req, energy);
            ev.printf("Send ackRN, value = %7.1f, (Arpees value =%7.1f) \n", fn,
                    fnCmp);
        } else {
            if (cos_temp < 0) {
                ev.printf("Don't send Ack relay, cos_temp=%7.0f<0 \n",
                        cos_temp);
            } else {
                ev.printf("Don't send Ack relay, Ereq=%7.0f > Eres= %7.1f \n",
                        e_req, energy);
            }
            delete (ackMess);
        }

    } else if (protocol == MLEACH) {
        Sensor *sensor = check_and_cast<Sensor*>(
                gate->getPathEndGate()->getOwnerModule());
        sensor->numberAckMax++;
        fn = distance2BS;
        ackMess->setValue(fn);
        mySend(ackMess, gate, false);
        ev.printf("Send ackRN, value = %7.1f \n", fn);
    } else if (protocol == ARPEES) {
        Sensor *sensor = check_and_cast<Sensor*>(
                gate->getPathEndGate()->getOwnerModule());
        sensor->numberAckMax++;
        ev << "Dem so ack relayMess " << sensor->numberAckMax << "\n";

        double xlength = this->xpos - sensor->xpos;
        double ylength = this->ypos - sensor->ypos;
        double distance = sqrt(xlength * xlength + ylength * ylength);
        double a, b, c;
        a = distance2BS;
        b = distance;
        c = sensor->distance2BS;
        double cos_temp = (b * b + c * c - a * a) / (2 * b * c);
        double sin_temp = sqrt(1 - cos_temp * cos_temp);
        //tinh nguoc lai de tim fmin
        fn = -energy * (b * b + c * c - a * a) / (2 * c * a);

        ackMess->setValue(fn);
        mySend(ackMess, gate, false);
        ev.printf("Send ackRN, value = %7.1f \n", fn);

    }

}
void Sensor::broadcastRequestRNMess() {
    RequestRN *rootMess = new RequestRN();
    rootMess->setKind(MSG_REQRN);
    int numberDeadth1_2=0;
    int numberNode1_2=0;

    for (cModule::GateIterator i(this); !i.end(); i++) {
        cGate *gate = i();
        if (gate->getType() == cGate::OUTPUT) {
            Sensor *sensor=check_and_cast<Sensor*>(gate->getPathEndGate()->getOwnerModule());

            if (sensor->distance2BS<this->distance2BS) {
                numberNode1_2++;
                if (sensor->status==STT_IS_DEATH) numberDeadth1_2++;
            }
//            if ((protocol==MYPROTOCOL)&&(numberDeadth1_2>=numberNode1_2)) {
//                rootMess->setFlag(1);
//            }
            RequestRN *mess = rootMess->dup();
            mySend(mess, gate, false);
        }
    }
    minAckCmpGate = NULL;
    minAckCmpGate = NULL;
    minAckValue = FMAX;
    minAckCmpValue = FMAX;
    //Thiet lap ack max=0
    numberAckMax = 0;
    delete (rootMess);
}
void Sensor::initNodes() {
    // Enter_Method_Silent("initNodes");
    cModule *parent = this->getParentModule();
    cModule *mod;
    int numNodes;



    numNodes = (int) parent->par("numNodes");

    for (int i = 2; i <= simulation.getLastModuleId(); i++) {
        int x, y, id;
        mod = (cModule *) simulation.getModule(i);

        if (strcmp(mod->getClassName(), "BaseStation") == 1) { //Sensor
            x = ((Sensor *) mod)->xpos;
            y = ((Sensor *) mod)->ypos;
        } else {
            x = ((BaseStation *) mod)->xpos;
            y = ((BaseStation *) mod)->ypos;
        }

        if (this->getId() != mod->getId()) {
            double xlength = (double) x - this->xpos;
            double ylength = (double) y - this->ypos;
            double distance = sqrt(xlength * xlength + ylength * ylength);
            if (distance < (double) this->transmitRange) {
                char idStr[2];
                sprintf(idStr, "%d to %d", this->getId(), i);
                char gateName[5] = "link";
                char *temp = strcat(gateName, idStr);
                cGate *ownGate = addGate(temp, cGate::OUTPUT);
                cGate *otherGate = mod->addGate(temp, cGate::INPUT);
                ownGate->connectTo(otherGate);
                numberNeighbor++;

                //gateOutArr->add(ownGate);
                //kiem tra xem co ket noi voi BS hay ko
                if (i == simulation.getLastModuleId()) {
                    ev << "ClassName " << mod->getClassName() << "\n";
                    ev << "Module " << id << "thiet lap ket lap voi BS \n";
                    hasToBSGate = true;
                    toBSGate = ownGate;
                }
                //hide link arow

                cDisplayString& connDispStr = ownGate->getDisplayString();
                connDispStr.parse("ls=,0");

            }
        }

    }
    //tinh khoang cach tu Node den BS

    BaseStation *bs = (BaseStation*) (simulation.getModule(
            simulation.getLastModuleId()));
    double xlength = this->xpos - bs->xpos;
    double ylength = this->ypos - bs->ypos;
    distance2BS = sqrt(xlength * xlength + ylength * ylength);
    base = bs;

    generateEvent();

}

cGate* Sensor::getOutGate(cGate *gateIn) {
    cGate *result;

    int sourceModuleId = gateIn->getPathStartGate()->getOwnerModule()->getId();
    for (cModule::GateIterator i(this); !i.end(); i++) {
        cGate *checkGate = i();
        if (checkGate->getType() == cGate::OUTPUT) {
            if (checkGate->getPathEndGate()->getOwnerModule()->getId()
                    == sourceModuleId) {
                result = checkGate;
                break;
            }
        }
    }
    return result;

}

void Sensor::energyCalculate(int messKind, int transmitType, double distance) {

    int packetSize;
    switch (messKind) {
    case MSG_DATA2RN:
        packetSize = 500 * 8;
        break;
    default:
        packetSize = 25 * 8;
        break;
    }

    if (transmitType == 201) { //transmit
        double amount = packetSize * 0.05
                + packetSize * distance * distance * 0.00001;
        energy = energy - amount;

        ev.printf("id= %d transmit %7.0f microJ, Eres=%7.0f microJ\n", id,
                amount, energy);
    } else { //receive
        double amount = packetSize * 0.05;
        energy = energy - amount;
        ev.printf("id= %d recieve %7.0f microJ, Eres=%7.0f microJ\n", id,
                amount, energy);

    }

}

void Sensor::broadCastMess(cMessage *msg, int code) {
    if (code == 0) { //to all neightbor
        for (cModule::GateIterator i(this); !i.end(); i++) {
            cGate *gate = i();
            if (gate->getType() == cGate::OUTPUT) {

                cMessage *mess = msg->dup();
                bool isCal = true;
                if (msg->getKind() == MSG_CHADV) {
                    isCal = false;
                    ev << "vao day\n";
                    cModule *mod =
                            (cModule *) gate->getPathEndGate()->getOwnerModule();

                    if (strcmp(mod->getClassName(), "Sensor") == 0) { //Sensor
                        Sensor *sensor = check_and_cast<Sensor*>(
                                gate->getPathEndGate()->getOwnerModule());
                        sensor->messCountMax++;

                    }

                }

                mySend(mess, gate, isCal);
            }
        }
    } else { //to ch member
        int timeSlot = 3;
        for (int i = 0; i < clusterMember->size(); i++) {
            cGate *in = (cGate*) clusterMember->get(i);
            cGate *out;
            if (protocol == MLEACH) {
                out = getOutGate(in);
            } else {
                out = in;
            }

            if (msg->getKind() == MSG_TDMA) {
                TDMAMessage *mess = check_and_cast<TDMAMessage *>(msg);
                mess->setTimeSlot(timeSlot);
                mess->setClusterMember(clusterMember->size());

            }
            mySend(msg->dup(), out, false);
        }
    }

}

double Sensor::distanceCal(double x1, double y1, double x2, double y2) {
    double distance;
    distance = sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
    return distance;
}

double Sensor::distanceCal(Sensor *sensor) {
    double distance = distanceCal(xpos, ypos, sensor->xpos, sensor->ypos);
    return distance;
}

void Sensor::resetRound() {
    Enter_Method_Silent("resetRound");
    currRound++;
    tempValue = 5000;
    messCountCurr = 0;
    messCountMax = 0;
    //null pinter

    chInGate = 0;
    //
    //xoa tuyen duong relay cho arpees va myprotocol

    relayNodeGate = 0;

    //
    int temp = (int) (1 / p);
    temp = 20;
    if (currRound % temp == 0) {
        controlCH = false;
    }
    //

    isInEvent = -1;
    //
    isFindRN = false;
    minAckCmpGate = NULL;
    minAckCmpGate = NULL;
    minAckValue = FMAX;
    minAckCmpValue = FMAX;
    //xoa to mau
    isColorize=false;
    //
    numberSttInfoMax = 0;
    numberSttInfo = 0;
    numberAckMax = 0;
    isCH = false;
    joinCHCurr = 0;
    joinCHMax = 0;
    numberClusterMember = 0;
    for (int i = 0; i < clusterMember->size(); i++) {
        clusterMember->remove(i);
    }

    currNumberData2CH = 0;
    numberDataInCH = 0;

    relayDataCount = 0;

    //reset display string
    if (status != STT_IS_DEATH) {
        cDisplayString& connDispStr = getDisplayString();
        connDispStr.parse("p=$xpos,$ypos;i=misc/node;is=vs");
        status = STT_IS_NORMAL;
    }

    for (cModule::GateIterator i(this); !i.end(); i++) {
        cGate *gate = i();
        if (gate->getType() == cGate::OUTPUT) {
            cDisplayString& connDispStra = gate->getDisplayString();
            connDispStra.parse("ls=,0");

        }
    }

}

void Sensor::handleClusterHeadJoin(cMessage *mess) {
    joinCHCurr++;
    CHJoin *msg = (CHJoin*) mess;
    if (msg->getStatus() != STT_IS_CH) {
        //Ko fai la CH cua cum khac
        if (clusterMember != NULL) {
            clusterMember->add(mess->getArrivalGate());
            ev << "Add thanh cong cluster member \n";
        } else {
            ev << "Co loi NULL pointer \n";
        }

    }

    if (joinCHCurr == joinCHMax) {

        TDMAMessage *mess = new TDMAMessage();
        mess->setKind(MSG_TDMA);
        broadCastMess(mess, 1); //to clustermember
        //cap nhat dataMax tren BS
        BaseStation *bs = (BaseStation*) simulation.getModule(
                simulation.getLastModuleId());
        if (clusterMember->size() != 0) {
            bs->numberDataMax += numberFrame;
        }

        ev << "Cap nhat numberDataMax tren BS " << bs->numberDataMax
                << " voi member=" << clusterMember->size() << "\n";
        delete (mess);
    }
}

void Sensor::handleTDMA(cMessage *mess) {
    TDMAMessage *msg = check_and_cast<TDMAMessage *>(mess);
    ev << "Nhan duoc ban tin TDMA voi TimeSlot =" << msg->getTimeSlot()
            << ", so member =" << msg->getClusterMember() << "\n";

    cMessage *msgData = new cMessage();
    msgData->setKind(MSG_DATA2CH);

    scheduleAt(simTime() + msg->getTimeSlot(), msgData);
}

void Sensor::handleData2CH_self(cMessage *mess) {
    //Xu li data2Ch o nut

    currNumberData2CH++;

    if (currNumberData2CH <= numberFrame) {
        ev << "Truyen data ve BS voi curr=" << currNumberData2CH << "/"
                << numberFrame << "Frame \n";
        DataToCHMessage *msg = new DataToCHMessage();
        msg->setKind(MSG_DATA2CH);
        if (chInGate != NULL) {
            mySend(msg, getOutGate(chInGate));
        } else {
            ev << "Co null pointer chInGarte\n";
            endSimulation();
        }

        if (currNumberData2CH < numberFrame) {
            cMessage *seltf = new cMessage();
            seltf->setKind(MSG_DATA2CH);
            //scheduleAt(simTime() + 3 * numberClusterMember + 1, seltf);
            scheduleAt(simTime() + 500, seltf);
        }

    }

}
void Sensor::handleData2CH_notself(cMessage *mess) {
    //XU li data2ch o ClusterHead
    numberDataInCH++;
    int memberId = mess->getSenderModule()->getId();
    ev << "ClusterHead nhan Data tu member " << numberDataInCH << "/"
            << clusterMember->size() << " (Member id =" << memberId << ") \n";
    if (numberDataInCH == clusterMember->size()) {
        numberDataInCH = 0;
        currNumberData2CH++;
        //gui ban tin ve relayNode
        if (currNumberData2CH <= numberFrame) {
            ev << "Gui ban tin ve relay Node voi " << currNumberData2CH << "/"
                    << numberFrame << "\n";
            Data2RNMessage *msg = new Data2RNMessage();
            msg->setKind(MSG_DATA2RN);
            handleData2RN(msg);
            //
            delete (msg);
            //
            BaseStation *bs = (BaseStation*) simulation.getModule(
                    simulation.getLastModuleId());
            bs->numberData++;
            ev << "Number data: " << bs->numberData << "/" << bs->numberDataMax
                    << "(NumberDataMax iin BS) \n";
            if (bs->numberData == bs->numberDataMax) {
                cMessage *endRoundMess = new cMessage();
                endRoundMess->setKind(MSG_ENDROUND);
                scheduleAt(simTime() + 500, endRoundMess);
            }
        }

    }

}

void Sensor::handleData2RN(cMessage *mess) {

    if (hasToBSGate) {
        if (isColorize==false) {
            cDisplayString& connDispStr = toBSGate->getDisplayString();
            connDispStr.parse("ls=#0080C0,2");
            cDisplayString& connDispStra = this->getDisplayString();
            connDispStra.parse("p=$xpos,$ypos;i=misc/node,red;is=vs");
            isColorize=true;
        }

       // connDispStr.parse("p=$xpos,$ypos;i=misc/node,red;is=vs");

        mySend(mess->dup(), toBSGate); //Gui ban tin den thang BS
        relayDataCount++;
        ev << "Gui ban tin ve bs " << relayDataCount << "/" << numberFrame
                << "\n";
    } else {
        if (relayNodeGate != NULL) {
            data2RNMessage = check_and_cast<Data2RNMessage*>(mess->dup());
            mySend(data2RNMessage, relayNodeGate);
            relayDataCount++;

        } else {

            if (isFindRN == false) {
                data2RNMessage = check_and_cast<Data2RNMessage*>(mess->dup());
                currNumberData2CH--;
                broadcastRequestRNMess();
                //reset lai gia tri de chuan bi nhan ban tin Ack
                numberAck = 0;
                ev << "Da xet false \n";
                isFindRN = true;
            } else {
                //ev << "Nhay vao test \n";
                //scheduleAt(simTime() + 1, mess->dup());
                //isFindRN=false;

            }
        }
    }

    //ko tim tuyen duong moi
    if (relayDataCount == numberFrame) {
        relayDataCount = 0;
       // if (protocol != MLEACH) {
            relayNodeGate = NULL;

        //}

        ev << "Da forward du data tren Relay \n";
    }

}

void Sensor::generateEvent() {
    Enter_Method_Silent("generateEvent");
    double t = p / (1 - p * (currRound % 20));

    double value = intuniform(0, 32678) * 1.0 / 32768;
    // double value= ((double) rand() / (32767 + 1.0));
    ev.printf("Gia tri random la %7.1f \n", value);
    if ((value < t) && (status != STT_IS_DEATH)) {
        if (controlCH == false) {
            controlCH = true;

            isCH = true;
            status = STT_IS_CH;
            base->totalCH++;
            if (protocol == MLEACH) {
                cDisplayString& connDispStr = getDisplayString();
                connDispStr.parse(
                        "p=$xpos,$ypos;i=misc/node,red;is=vs");
                bubble("Candidate");
                ClusterHeadAdv *mess = new ClusterHeadAdv();
                mess->setKind(MSG_CHADV);
                mess->setSrcAddress(id);
                broadCastMess(mess, 0);
                delete (mess);
            } else {
                cDisplayString& connDispStr = getDisplayString();
                connDispStr.parse("p=$xpos,$ypos;i=misc/node,red;is=vs;");
                bubble("Candidate");

                this->isInEvent = base->eventId;
                base->eventId++;
                cMessage *myGenEvent = new cMessage();
                myGenEvent->setKind(MSG_MY_GEN_EVENT);
                scheduleAt(simTime() + 1, myGenEvent);
            }

        } else {
            ev << "Control CH = true \n";
        }

    }

}

double Sensor::energyTool(int messKind, int transmitType, double distance) {
    double result = 0;
    int packetSize;
    switch (messKind) {
    case MSG_DATA2RN:
        packetSize = 500 * 8;
        break;
    default:
        packetSize = 25 * 8;
        break;
    }
    if (transmitType == TRANSMIT) { //transmit
        result = packetSize * 0.05 + packetSize * distance * distance * 0.00001;
    } else { //receive
        result = packetSize * 0.05;
    }
    return result;
}

void Sensor::myScheduleAt(simtime_t t, cMessage *msg) {
    Enter_Method_Silent("aaa");
    StatusInfo *mess = new StatusInfo();
    mess->setKind(MSG_STATUSINFO);
    mess->setIdCH(-1);
    scheduleAt(t, mess);
}

cGate *Sensor::getInGate(Sensor *sensor) {
    cGate *result;
    for (cModule::GateIterator i(this); !i.end(); i++) {
        cGate *gate = i();
        if (gate->getType() == cGate::OUTPUT) {
            Sensor *sensor = check_and_cast<Sensor*>(
                    gate->getPathEndGate()->getOwnerModule());
            if (sensor->id == this->id) {
                result = gate->getPathEndGate();
                break;
            }

        }
    }
    return result;
}

void Sensor::hanndleMyGenEvent(cMessage *mess) {

    StatusInfo *msg = new StatusInfo();
    msg->setKind(MSG_STATUSINFO);
    msg->setIdCH(getId());
    scheduleAt(simTime() + 1, msg);
    status = STT_IS_CH;

    StatusInfo *seltf = new StatusInfo();
    seltf->setIdCH(-1);
    for (cModule::GateIterator i(this); !i.end(); i++) {
        cGate *gate = i();
        if (gate->getType() == cGate::OUTPUT) {
            cModule *mod = gate->getPathEndGate()->getOwnerModule();
            if (strcmp(mod->getClassName(), "BaseStation") == 1) {
                //Sensor
                Sensor *sensor = check_and_cast<Sensor *>(
                        gate->getPathEndGate()->getOwnerModule());
                if ((distanceCal(sensor) < sensorRange)
                        && (sensor->isInEvent == -1)
                        && (sensor->status != STT_IS_DEATH)) {
                    sensor->isInEvent = this->isInEvent;
                    ev << "Da xet seltf mess tren sensor dau xa " << sensor->id
                            << " idCH=" << seltf->getId() << "\n";
                    sensor->myScheduleAt(simTime() + 1, NULL);
                    clusterMember->add(gate);

                    cDisplayString& connDispStr = gate->getDisplayString();
                    connDispStr.parse("ls=,1");
                    cDisplayString& connDispStra = sensor->getDisplayString();
                    connDispStra.parse("p=$xpos,$ypos;i=misc/node,green;is=vs");

                } else {
                    ev << "Khong xet\n";
                }
            }
        }
    }
    numberSttInfoMax = clusterMember->size();
    delete (seltf);

    ev << "Da chay xong handle o day\n";
}

void Sensor::handleStatusInfo(cMessage *mess) {
    ev << "Nhan dc stt info\n";
    StatusInfo *msg = check_and_cast<StatusInfo*>(mess);
    if (msg->getIdCH() != -1) {
        chInGate = msg->getArrivalGate();
        ev << "Da thiet lap chInGate voi " << msg->getSenderModule()->getId()
                << "\n";
    } else {
        if (status == STT_IS_CH) {
            numberSttInfo++;
            ev << "Tai CT nhan dc StatusInfo " << numberSttInfo << "/"
                    << numberSttInfoMax << "\n";
            if (numberSttInfo == numberSttInfoMax) {
                TDMAMessage *mess = new TDMAMessage();
                mess->setKind(MSG_TDMA);
                broadCastMess(mess, 1);
                BaseStation *bs = (BaseStation*) simulation.getModule(
                        simulation.getLastModuleId());
                if (clusterMember->size() != 0) {
                    bs->numberDataMax += numberFrame;
                }

                ev << "Cap nhat numberDataMax tren BS " << bs->numberDataMax
                        << " voi member=" << clusterMember->size() << "\n";
                delete (mess);
            }
        }
    }
}

void Sensor::finish() {
    recordScalar("Node E:", energy);
}



void Sensor::mySend(cMessage *mess, cGate *gate, bool isCalEnergy) {
    if ((mess != NULL) && (gate != NULL)) {
        double distance;
        if (hasToBSGate) {
            BaseStation *bs = check_and_cast<BaseStation*>(
                    simulation.getModule(simulation.getLastModuleId()));
            double xlength = this->xpos - bs->xpos;
            double ylength = this->ypos - bs->ypos;
            distance = sqrt(xlength * xlength + ylength * ylength);
        } else {
            Sensor *sensor = (Sensor*) gate->getPathEndGate()->getOwnerModule();
            double xlength = this->xpos - sensor->xpos;
            double ylength = this->ypos - sensor->ypos;
            distance = sqrt(xlength * xlength + ylength * ylength);
            ev.printf("Distance = %7.7f", distance);
        }
        if (isCalEnergy == true) {
            energyCalculate(mess->getKind(), TRANSMIT, distance);
        }

        send(mess, gate);
    } else {
        if (mess == NULL) {
            ev << "Co loi NULL pointer tai ham send: Message NULL pointer \n";
        } else {
            ev << "Co loi NULL pointer tai ham send: gate NULL pointer \n";
        }

    }

}

void Sensor::generateMessage2BS()

{
    Enter_Method_Silent("generateMessage2BS");
    Data2RNMessage *mess = new Data2RNMessage();
    mess->setKind(MSG_DATA2RN);
    scheduleAt(simTime() + 1000, mess);

}

void Sensor::broadCastStatusInfo() {
    Enter_Method_Silent("broadCastStt");
    StatusInfo *mess = new StatusInfo();
    mess->setKind(MSG_STATUSINFO);

    for (cModule::GateIterator i(this); !i.end(); i++) {
        cGate *gate = i();
        if (gate->getType() == cGate::OUTPUT) {
            Sensor *sensor = check_and_cast<Sensor*>(
                    gate->getPathEndGate()->getOwnerModule());
            if (sensor->isInEvent == this->isInEvent) {
                mySend(mess->dup(), gate, false);
            }
        }
    }
    delete (mess);

}
void Sensor::temp() {
    Enter_Method_Silent("temp");
    cMessage *msg = new cMessage();
    msg->setKind(MSG_STATUSINFO);
    scheduleAt(simTime(), msg);

}
void Sensor::handleClusterHeadAdv(cMessage *mess) {
    messCountCurr++;
    ClusterHeadAdv *temp = (ClusterHeadAdv*) mess;

    ev << "Nhan duoc " << messCountCurr << "/" << messCountMax
            << " ban tin CH adv tu CH= " << temp->getSrcAddress() << "\n";
    if (messCountCurr <= messCountMax) {
        Sensor *sensor = check_and_cast<Sensor*>(mess->getSenderModule());
        double distance = distanceCal(sensor);
        if (distance < tempValue) {
            tempValue = distance;
            chInGate = mess->getArrivalGate();
        }
    }

    if (messCountCurr == messCountMax) {

        CHJoin *msg = new CHJoin();
        msg->setKind(MSG_CLUSTERJOIN);
        msg->setStatus(status);

        cGate *out = getOutGate(chInGate);
        if (status != STT_IS_CH) {

            cDisplayString& connDispStr = out->getDisplayString();
            connDispStr.parse("ls=,1");
            cDisplayString& connDispStra = getDisplayString();
            connDispStra.parse("p=$xpos,$ypos;i=misc/node,green;is=vs");
        } else {
            ev << "Nhay vao STT IS CH \n";
        }

        mySend(msg, out, false);
        Sensor *sensor = check_and_cast<Sensor*>(
                out->getPathEndGate()->getOwnerModule());
        sensor->joinCHMax++;

    }

}

